using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Drawing;
using System.Drawing.Imaging;
using System.Drawing.Drawing2D;

/// <summary>
/// Summary description for AuthenticImage
/// </summary>
public class AuthenticImage
{
    #region Members

    private string m_Text = "";
    private int m_Width = 0;
    private int m_Height = 0;
    private string m_FontFamilyName = "";
    private Bitmap m_Image = null;

    private Random m_Random = new Random();

    #endregion Members

    #region Properties

    public string Text
    {
        get { return this.m_Text; }
    }
    public Bitmap Image
    {
        get { return this.m_Image; }
    }
    public int Width
    {
        get { return this.m_Width; }
    }
    public int Height
    {
        get { return this.m_Height; }
    }

    public string FontFamilyName
    {
        get { return this.m_FontFamilyName; }
    }

    #endregion Properties

    #region Contructors

    /// <summary>
    /// Initializes a new instance of the CaptchaImage class using the
    /// specified text, width and height.
    /// </summary>
    /// <param name="pText"></param>
    /// <param name="pWidth"></param>
    /// <param name="pHeight"></param>
    public AuthenticImage(string pText, int pWidth, int pHeight)
    {
        this.m_Text = pText;
        this.SetDimensions(pWidth, pHeight);
        this.GenerateImage();
    }

    /// <summary>
    /// Initializes a new instance of the CaptchaImage class using the
    /// specified text, width, height and font family name.
    /// </summary>
    /// <param name="pText"></param>
    /// <param name="pWidth"></param>
    /// <param name="pHeight"></param>
    /// <param name="pFontFamilyName"></param>
    public AuthenticImage(string pText, int pWidth, int pHeight, string pFontFamilyName)
    {
        this.m_Text = pText;
        this.SetDimensions(pWidth, pHeight);
        this.SetFontFamily(pFontFamilyName);
        this.GenerateImage();
    }

    #endregion Contructors

    #region Destructor

    /// <summary>
    /// This member overrides Object.Finalize.
    /// </summary>
    ~AuthenticImage()
    {
        Dispose(false);
    }

    #endregion Destructor

    #region Private Methods
    /// <summary>
    /// Sets the image width and height.
    /// </summary>
    /// <param name="width"></param>
    /// <param name="height"></param>
    /// <exception cref="ArgumentOutOfRangeException"></exception>
    private void SetDimensions(int pWidth, int pHeight)
    {
        // Check the width and height.
        if (pWidth <= 0)
            throw new ArgumentOutOfRangeException("Width", pWidth, "Argument out of range, must be greater than zero.");
        if (pHeight <= 0)
            throw new ArgumentOutOfRangeException("Height", pHeight, "Argument out of range, must be greater than zero.");
        this.m_Width = pWidth;
        this.m_Height = pHeight;
    }

    /// <summary>
    /// Sets the font used for the image text.
    /// </summary>
    /// <param name="pFontFamilyName"></param>
    private void SetFontFamily(string pFontFamilyName)
    {
        // If the named font is not installed, default to a system font.
        try
        {
            Font font = new Font(pFontFamilyName, 14F);
            this.m_FontFamilyName = pFontFamilyName;
            font.Dispose();
        }
        catch
        {
            this.m_FontFamilyName = System.Drawing.FontFamily.GenericSerif.Name;
        }
    }

    /// <summary>
    /// Creates the bitmap image.
    /// </summary>
    private void GenerateImage()
    {
        // Create a new 32-bit bitmap image.
        Bitmap bitmap = new Bitmap(this.m_Width, this.m_Height, PixelFormat.Format32bppArgb);

        // Create a graphics object for drawing.
        Graphics g = Graphics.FromImage(bitmap);
        g.SmoothingMode = SmoothingMode.AntiAlias;
        Rectangle rect = new Rectangle(0, 0, this.m_Width, this.m_Height);

        // Fill in the background.
        HatchBrush hatchBrush = new HatchBrush(HatchStyle.SmallConfetti, Color.LightGray, Color.White);
        g.FillRectangle(hatchBrush, rect);

        // Set up the text font.
        SizeF size;
        float fontSize = rect.Height + 1;
        Font font;
        // Adjust the font size until the text fits within the image.
        do
        {
            fontSize--;
            font = new Font(this.m_FontFamilyName, fontSize, FontStyle.Bold);
            size = g.MeasureString(this.m_Text, font);
        } while (size.Width > rect.Width);

        // Set up the text format.
        StringFormat format = new StringFormat();
        format.Alignment = StringAlignment.Center;
        format.LineAlignment = StringAlignment.Center;

        // Create a path using the text and warp it randomly.
        GraphicsPath path = new GraphicsPath();
        path.AddString(this.m_Text, font.FontFamily, (int)font.Style, font.Size, rect, format);
        float v = 4F;
        PointF[] points =
            {
                new PointF(this.m_Random.Next(rect.Width) / v, this.m_Random.Next(rect.Height) / v),
                new PointF(rect.Width - this.m_Random.Next(rect.Width) / v, this.m_Random.Next(rect.Height) / v),
                new PointF(this.m_Random.Next(rect.Width) / v, rect.Height - this.m_Random.Next(rect.Height) / v),
                new PointF(rect.Width - this.m_Random.Next(rect.Width) / v, rect.Height - this.m_Random.Next(rect.Height) / v)
            };
        Matrix matrix = new Matrix();
        matrix.Translate(0F, 0F);
        path.Warp(points, rect, matrix, WarpMode.Perspective, 0F);

        // Draw the text.
        hatchBrush = new HatchBrush(HatchStyle.LargeConfetti, Color.Green, Color.Green);
        g.FillPath(hatchBrush, path);

        // Add some random noise.
        int m = Math.Max(rect.Width, rect.Height);
        for (int i = 0; i < (int)(rect.Width * rect.Height / 20F); i++)
        {
            int x = this.m_Random.Next(rect.Width);
            int y = this.m_Random.Next(rect.Height);
            int w = this.m_Random.Next(m / 50);
            int h = this.m_Random.Next(m / 50);
            g.FillEllipse(hatchBrush, x, y, w, h);
        }

        // Clean up.
        font.Dispose();
        hatchBrush.Dispose();
        g.Dispose();

        // Set the image.
        this.m_Image = bitmap;
    }
    #endregion Private Methods

    #region Public Methods

    /// <summary>
    /// Releases all resources used by this object.
    /// </summary>
    public void Dispose()
    {
        GC.SuppressFinalize(this);
        this.Dispose(true);
    }

    #endregion Public Methods

    #region Virtual Methods
    /// <summary>
    /// Custom Dispose method to clean up unmanaged resources.
    /// </summary>
    /// <param name="pDisposing"></param>
    protected virtual void Dispose(bool pDisposing)
    {
        // disposing of the bitmap
        if (pDisposing)
            this.Image.Dispose();
    }
    #endregion Virtual Methods

}
